﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Modelo
{
    [Serializable]
    public abstract class Bomba : IColisionable
    {
        protected Mapa mapa;
        protected decimal retardo;
        protected int expansion;
        protected Posicion posicion;
        protected List<Posicion> posicionesAfectadas;

        public Bomba(int retardo, int expansion, Mapa mapa)
        {
            this.retardo = retardo;
            this.expansion = expansion * mapa.getTamCelda();//asi la expansion es por celdas
            this.posicionesAfectadas = new List<Posicion>();
            this.mapa = mapa;
        }

        public void serDejada(Posicion pos)
        {
            this.posicion = pos;
        }

        public Posicion getPosicion()
        {
            return posicion;
        }

        public bool RestarTiempo(TimeSpan time)
        {
            decimal segundos = Convert.ToDecimal(time.Milliseconds)/1000;
            retardo -= segundos;
            if (retardo <= 0)
            {
                explotar();
                return true;
            }
            return false;
        }

        public List<Posicion> GetPosicionesAfectadas()
        {
            return posicionesAfectadas;
        }

        public List<Posicion> VerPosicionesAfectadas()
        {
            if (posicion == null)
                return null;

            posicionesAfectadas = new List<Posicion>();
            posicionesAfectadas.Add(posicion);
            Posicion posicionAfectada;
            bool chocoMasX = false;
            bool chocoMenosX = false;
            bool chocoMasY = false;
            bool chocoMenosY = false;
            for (int x = 1; x <= expansion; x++)
            {
                posicionAfectada = new Posicion(posicion.getX() + x, posicion.getY());
                if (posicionAfectada.getX() <= mapa.getCantPuntosX() && chocoMasX == false)
                {
                    posicionesAfectadas.Add(posicionAfectada);
                    if (Celdas.Obtenercelda(posicionAfectada, mapa).getCaminable() == false)
                        chocoMasX = true;
                }
                posicionAfectada = new Posicion(posicion.getX() - x, posicion.getY());
                if (posicionAfectada.getX() >= 0 && chocoMenosX == false)
                {
                    posicionesAfectadas.Add(posicionAfectada);
                    if (Celdas.Obtenercelda(posicionAfectada, mapa).getCaminable() == false)
                        chocoMenosX = true;
                }
            }
            for (int y = 1; y <= expansion; y++)
            {
                posicionAfectada = new Posicion(posicion.getX(), posicion.getY() + y);
                if (posicionAfectada.getY() <= mapa.getCantPuntosY() && chocoMasY == false)
                {
                    posicionesAfectadas.Add(posicionAfectada);
                    if (Celdas.Obtenercelda(posicionAfectada, mapa).getCaminable() == false)
                        chocoMasY = true; 
                }
                posicionAfectada = new Posicion(posicion.getX(), posicion.getY() - y);
                if (posicionAfectada.getY() >= 0 && chocoMenosY == false)
                {
                    posicionesAfectadas.Add(posicionAfectada);
                    if (Celdas.Obtenercelda(posicionAfectada, mapa).getCaminable() == false)
                        chocoMenosY = true;
                }
            }

            return posicionesAfectadas;
        }

        public virtual void AfectarBloques(List<Posicion> posicionesAfectadas, int potenciaDeDestruccion)
        {
            List<Celda> celdasAfectadas = mapa.verCeldasAfectadas(posicionesAfectadas);
            foreach (Celda celda in celdasAfectadas)
            {
                if (celda.ObtenerBloque() != null)
                {
                    Bloque bloque = celda.ObtenerBloque();
                    bloque.hacerDano(potenciaDeDestruccion);
                    if (bloque.getResistencia() == 0)
                        mapa.eliminarBloqueDestruido(bloque, celda);
                }
            }
        }

        public virtual void AfectarEnemigos(List<Posicion> posicionesAfectadas, int potenciaDeDestruccion)
        {
            List<Enemigo> enemigosAfectados = mapa.verEnemigosAfectados(posicionesAfectadas);
            foreach (Enemigo enemigo in enemigosAfectados)
            {
                enemigo.restarResistencia(potenciaDeDestruccion);
                if (enemigo.obtenerResistencia() == 0)
                    mapa.eliminarEnemigoDestruido(enemigo);
            }
        }

        public void AfectarBombita(List<Posicion> posicionesAfectadas)
        {
            Bombita bombita = mapa.obtenerJugador();
            foreach (Posicion pos in posicionesAfectadas)
            {
                if (Celdas.Obtenercelda(pos, mapa) == Celdas.Obtenercelda(new Posicion(bombita.getPosX(),bombita.getPosY()), mapa))
                {
                    bombita.perderVida();
                    mapa.reiniciarNivel(mapa);
                    return;
                }
            }
        }

        public abstract void explotar();

        #region IColisionable Members

        public void recibirColision(IColisionable elOtro)
        {
            elOtro.manejarColisionCon(this);
        }

        public void manejarColisionCon(Bombita elOtro)
        {
            //No lo tiene que dejar caminar por encima
        }

        public  void manejarColisionCon(Enemigo elOtro)
        {
            //No lo tiene que dejar caminar por encima
        }

        public void manejarColisionCon(PowerUp elOtro)
        {
            //No pasa nada
        }

        public void manejarColisionCon(Bomba elOtro)
        {
            //No pasa nada aunque no deberia pasar.
        }
    
        public  int getPosX()
        {
            return this.posicion.getX();
        }

        public  int  getPosY()
        {
            return this.posicion.getY();
        }

        public  int  getTamanio()
        {
            return 1;//tienen tamanio 1 las bombas
        }

        #endregion

        public decimal getRetardo()
        {
            return retardo;
        }

        public int getExpansion()
        {
            return expansion;
        }

        public void disminuirRetardo(int disminucionRetardo)
        {
            if (retardo > 0 && retardo < 100)
                retardo -= (retardo*disminucionRetardo/100);
        }
    }
}
